package seabattle;

import seabattle.field.BattleField;
import seabattle.field.Message;
import seabattle.io.ConsolePrinter;
import seabattle.io.KeyboardReader;
import seabattle.io.Reflector;
import seabattle.movements.ComputerMovement;
import seabattle.movements.Movement;
import seabattle.movements.PlayerMovement;
import seabattle.ship.Coordinates;
import seabattle.ship.RandomShipGenerator;
import seabattle.ship.ShipsGenerator;

public class ConsoleEngine {
	public static final int MAX_LOOP_COUNT = 10000;
	private final ConsolePrinter printer = new ConsolePrinter();
	private final Reflector screen = new Reflector(printer);
	private final BattleField playerField = new BattleField();
	private final BattleField computerField = new BattleField();
	private final ShipsGenerator shipGenerator = new ShipsGenerator(new RandomShipGenerator());
	private final Movement player = new PlayerMovement(new KeyboardReader());
	private final Movement computer = new ComputerMovement();

	public void run() {
		shipGenerator.generateOn(playerField);
		shipGenerator.generateOn(computerField);
		computerField.setVisible(false);
		int count = 0;
		do {
			screen.drawFields(playerField, computerField);
			if (!playerMove()) {
				break;
			}
			if (!computerField.checkAliveShips()) {
				printer.print("<<< YOU WIN >>>");
				break;
			}
			computerMove();
			if (!playerField.checkAliveShips()) {
				printer.print("<<< YOU LOSE>>>");
				break;
			}
			count++;
		} while (count < MAX_LOOP_COUNT);
	}

	private boolean playerMove() {
		int count = 0;
		do {
			Coordinates coordinates = player.getShot();
			if (coordinates == null) {
				return false;
			}
			Message shotResult = computerField.catchingShot(coordinates);
			printer.print(shotResult.text());
			if (shotResult == Message.AGAIN) {
				// do nothing
			} else if (shotResult == Message.HIT) {
				screen.drawFields(playerField, computerField);
				if (!computerField.checkAliveShips()) {
					break;
				}
			} else if (shotResult == Message.MISS) {
				break;
			}
			count++;
		} while (count < MAX_LOOP_COUNT);
		return true;
	}

	private boolean computerMove() {
		int count = 0;
		do {
			Coordinates coordinates = computer.getShot();
			Message shotResult = playerField.catchingShot(coordinates);
			if (shotResult == Message.HIT) {
				if (!playerField.checkAliveShips()) {
					break;
				}
			}
			if (shotResult == Message.MISS) {
				break;
			}
			count++;
		} while (count < MAX_LOOP_COUNT);
		return true;
	}

}
